package helper

import (
	mc "bbtradeByGo/model/match"
	rmc "bbtradeByGo/model/match/model"
	"bbtradeByGo/pkg/email"
	"bbtradeByGo/pkg/gmysql"
	"bbtradeByGo/pkg/logging"
	"errors"
	"math/big"
	"time"
)

//DoMatch 执行撮合入口
func DoMatch(purchase, sale *rmc.MCondition, sellFee, buyFee float64, number, price float64, taker int) {
	//一、买单成功，撮合基础币
	// 1.更新order
	OrderUpdate(purchase, sellFee, buyFee, number, price)

	//2.创建trade表
	BuyTradeAdd(purchase, buyFee, number, price, taker)

	//二、卖单成交，撮合目标币
	OrderUpdate(sale,  sellFee, buyFee, number, price)
	//创建trade表
	SellTradeAdd(sale, sellFee, number, price, taker)

	//三、更新资产
	if purchase.Uid != sale.Uid {
		//3.1 买入
		//3.1.1 减少基础币的资产
		err := AssetsBSub(purchase, number, price)
		if err != nil {
			email.SendMail("service.match.helper.DoMatch AssetsBsub", err.Error())
			logging.Error("service.match.helper.DoMatch AssetsBsub err:", err)
		}
		//3.1.2 增加目标币的资产
		AssetsCAdd(purchase, buyFee, number)

		//3.2 卖出
		//3.2.1 增加基础币的资产
		AssetsBAdd(sale, number, sellFee, price)
		// 3.2.2 减少卖出币的资产
		err = AssetsCSub(sale, number)
		if err != nil {
			email.SendMail("service.match.helper.DoMatch AssetsCSub", err.Error())
			logging.Error("service.match.helper.DoMatch AssetsCSub err:", err)
		}
	}else {
       //买入
       //市价买入不冻结资产
       if purchase.Tradetype == 1 {
		   num      := big.NewFloat(number)
		   bigPrice := big.NewFloat(price)
		   selFee   := big.NewFloat(sellFee)
		   logging.Info("service.match.helper.DoMatch num:", num)
		   logging.Info("service.match.helper.DoMatch bigPrice1:", bigPrice)
		   logging.Info("service.match.helper.DoMatch selFee1:", selFee)

		   mulResult := num.Mul(num, selFee)
		   logging.Info("service.match.helper.DoMatch mulResult1:", mulResult)

		   totalPrice, _  := mulResult.Mul(mulResult, bigPrice).Float64()
		   logging.Info("service.match.helper.DoMatch totalPrice1:", totalPrice)

		   _, err := gmysql.DB.Exec(`update abc_currency_user set number = number - ? where uid = ? and currency_id = ?`,
				totalPrice, purchase.Uid, purchase.BaseCurrencyId)
			if err != nil {
				email.SendMail("service.match.helper.DoMatch err1", err.Error())
				logging.Error("service.match.helper.DoMatch err1:", err)
			}
		}else {
		   num      := big.NewFloat(number)
		   bigPrice := big.NewFloat(price)
		   selFee   := big.NewFloat(sellFee)
		   purchasePrice := big.NewFloat(purchase.Price)
		   logging.Info("service.match.helper.DoMatch num:", num)
		   logging.Info("service.match.helper.DoMatch bigPrice2:", bigPrice)
		   logging.Info("service.match.helper.DoMatch selFee2:", selFee)
		   logging.Info("service.match.helper.DoMatch purchasePrice:", purchasePrice)


		   mulResult := num.Mul(num, selFee)
		   logging.Info("service.match.helper.DoMatch mulResult2:", mulResult)

		   totalPrice, _  := mulResult.Mul(mulResult, bigPrice).Float64()
		   logging.Info("service.match.helper.DoMatch totalPrice3:", totalPrice)

		   purchasePri, _  := num.Mul(big.NewFloat(number), purchasePrice).Float64()
		   logging.Info("service.match.helper.DoMatch purchasePri:", purchasePri)

			_, err := gmysql.DB.Exec(`update abc_currency_user set number = number - ?,number_frz = number_frz - ? where uid = ? and currency_id = ?`,
				totalPrice, purchasePri, purchase.Uid, purchase.BaseCurrencyId)
			if err != nil {
				email.SendMail("service.match.helper.DoMatch err2", err.Error())
				logging.Error("service.match.helper.DoMatch err2:", err)
			}
		}
       //卖出
		num      := big.NewFloat(number)
		buFee   := big.NewFloat(buyFee)
		logging.Info("service.match.helper.DoMatch num:", num)
		logging.Info("service.match.helper.DoMatch buFee:", buFee)

		mulRes, _ := num.Mul(num, buFee).Float64()
		logging.Info("service.match.helper.DoMatch mulRes:", mulRes)

		_, err := gmysql.DB.Exec(`update abc_currency_user set number = number - ?,number_frz = number_frz - ? where uid = ? and currency_id = ?`,
			mulRes, number, purchase.Uid, purchase.CurrencyId)
		if err != nil {
			email.SendMail("service.match.helper.DoMatch err3", err.Error())
			logging.Error("service.match.helper.DoMatch err3:", err)
		}
	}
}
//OrderUpdate 订单更新
func OrderUpdate(order *rmc.MCondition, sellFee, buyFee float64, number, price float64) {
	var orderStatus int
	if number > order.Surplus {
		logging.Error("service.match.helper.OrderUpdate err:", order)
		return
	}
	if number == order.Surplus {
		//全部成交
		orderStatus = 2
	}else {
		//部分成交
		orderStatus = 1
	}

	orderTrademoney     := big.NewFloat(order.Trademoney)
	orderSurplus        := big.NewFloat(order.Surplus)
	BigNumber      := big.NewFloat(number)
	BigPrice      := big.NewFloat(price)
	logging.Info("service.match.helper.OrderUpdate orderTrademoney:", orderTrademoney)
	logging.Info("service.match.helper.OrderUpdate orderSurplus:", orderSurplus)
	logging.Info("service.match.helper.OrderUpdate BigNumber:", BigNumber)
	logging.Info("service.match.helper.OrderUpdate BigPrice:", BigPrice)


	mulResult     := BigNumber.Mul(BigPrice, BigNumber)
	trademoney, _ := orderTrademoney.Add(orderTrademoney, mulResult).Float64()

	logging.Info("service.match.helper.OrderUpdate mulResult:", mulResult)
	logging.Info("service.match.helper.OrderUpdate trademoney:", trademoney)

	surplus, _    := orderSurplus.Sub(orderSurplus, big.NewFloat(number)).Float64()
	logging.Info("service.match.helper.OrderUpdate surplus:", surplus)


	fields := rmc.Field{
		//基础币种成交数量
		Trademoney: trademoney,
		//剩余量
		Surplus: surplus,
		//最终订单状态
		OrderStatus: orderStatus,
	}
    err := mc.OrderUpDate(order, &fields)
    if err != nil {
    	email.SendMail("service.match.helper.OrderUpdate", err.Error())
    	logging.Error("service.match.helper.OrderUpdate err:", err)
	}
}

//BuyTradeAdd 撮合生成
func BuyTradeAdd(order *rmc.MCondition, buyFee float64, number, price float64, taker int) {
     //3.计算手续费
	num            := big.NewFloat(number)
	buFee          := big.NewFloat(buyFee)
	logging.Info("service.match.helper.BuyTradeAdd num:", num)
	logging.Info("service.match.helper.BuyTradeAdd buFee:", buFee)

	mulResult, _   := num.Mul(num, buFee).Float64()
	logging.Info("service.match.helper.BuyTradeAdd mulResult:", mulResult)

	mc.GenerateTrade(&rmc.Field{
     	UId: order.Uid,
     	OrderId: order.Id,
     	BaseCurrencyId: order.BaseCurrencyId,
     	CurrencyId: order.CurrencyId,
     	Price: price,
     	Number: number,
     	Poundage: mulResult,
     	CreateTime: int(time.Now().Unix()),
     	Type: order.Type, //0->买入
     	Tradetype: order.Tradetype,
     	Taker: taker,
	 })
}

//SellTradeAdd 撮合生成
func SellTradeAdd(order *rmc.MCondition, sellFee float64, number, price float64, taker int) {
	//3.计算手续费
	num            := big.NewFloat(number)
	selFee         := big.NewFloat(sellFee)
	logging.Info("service.match.helper.SellTradeAdd num:", num)
	logging.Info("service.match.helper.SellTradeAdd selFee:", selFee)

	mulResult, _   := num.Mul(num, selFee).Float64()
	logging.Info("service.match.helper.SellTradeAdd mulResult:", mulResult)


	mc.GenerateTrade(&rmc.Field{
		UId: order.Uid,
		OrderId: order.Id,
		BaseCurrencyId: order.BaseCurrencyId,
		CurrencyId: order.CurrencyId,
		Price: price,
		Number: number,
		Poundage: mulResult,
		CreateTime: int(time.Now().Unix()),
		Type: order.Type, //0->买入
		Tradetype: order.Tradetype,
		Taker: taker,
	})
}

//AssetsBsub 买入  基础币资产减少
func AssetsBSub(order *rmc.MCondition, number, price float64) error{
    condition := rmc.Condition{
    	UId: order.Uid,
    	CurrencyId: order.BaseCurrencyId,
	}
    assets, err := mc.AssetsList(&condition)
    if err != nil {
    	email.SendMail("service.match.helper.AssetsBsub err:", err.Error())
    	logging.Error("service.match.helper.AssetsBsub err:", err)
	}
    if len(assets) == 0 {
    	return errors.New("service.match.helper AssetsBsub 没有资产")
	}else {

		num        := big.NewFloat(number)
		pri        := big.NewFloat(price)
		logging.Info("service.match.helper.AssetsBSub num:", num)
		logging.Info("service.match.helper.AssetsBSub pri:", pri)

		//换算成基础币的数量
		mulResult, _ := num.Mul(num, pri).Float64()
		logging.Info("service.match.helper.AssetsBSub mulResult:", mulResult)


		assetsNumber    := big.NewFloat(assets[0].Number)
		assetsNumberWtd := big.NewFloat(assets[0].NumberWtd)
		logging.Info("service.match.helper.AssetsBSub assetsNumber:", assetsNumber)
		logging.Info("service.match.helper.AssetsBSub assetsNumberWtd:", assetsNumberWtd)

		//判断可用资产是否足够
		numberCanUse, _ := assetsNumber.Sub(assetsNumber, assetsNumberWtd).Float64()
		logging.Info("service.match.helper.AssetsBSub numberCanUse:", numberCanUse)

		if numberCanUse < mulResult {
			return errors.New("service.match.helper AssetsBsub 基础币资产不足")
		}

		//减
		bigNumberB  := big.NewFloat(mulResult)
		logging.Info("service.match.helper.AssetsBSub bigNumberB:", bigNumberB)

		subNumber, _ := assetsNumber.Sub(assetsNumber, bigNumberB).Float64()
		logging.Info("service.match.helper.AssetsBSub subNumber:", subNumber)



		//所有的卖出单和限价单，都需要冻结资产
		//限价单需要解除冻结资产
		//判断冻结数量和要使用的是否一致
		if order.Tradetype == 0 || order.Type == 0 {
			//买入价格和卖出价格可能不一致  当买入价格为110，成交价是100，减少的冻结数量应该为下单的价作110为比例
			orderPrice   := big.NewFloat(order.Price)
			logging.Info("service.match.helper.AssetsBSub orderPrice:", orderPrice)

			numberF, _   := orderPrice.Mul(big.NewFloat(number), orderPrice).Float64()
			logging.Info("service.match.helper.AssetsBSub numberF:", numberF)

			// 冻结资产的数量
			frzNumber :=big.NewFloat(assets[0].NumberFrz)
			logging.Info("service.match.helper.AssetsBSub frzNumber:", frzNumber)
			bigNumberF  := big.NewFloat(numberF)
			logging.Info("service.match.helper.AssetsBSub bigNumberF:", bigNumberF)
			//减
			subFreeze , _ := frzNumber.Sub(frzNumber, bigNumberF).Float64()
			logging.Info("service.match.helper.AssetsBSub subFreeze:", subFreeze)

			if subFreeze < 0 {
				return errors.New("service.match.helper AssetsBsub 基础币冻结资产不足")
			}
			fields := rmc.Assets{
				Number: subNumber,
				NumberFrz: subFreeze,
			}
			con := rmc.Condition{
				Id: assets[0].Id,
			}
			err := mc.AssetsUpdate(&con, &fields)
			if err != nil {
				email.SendMail("service.match.helper.AssetsBsub err1", err.Error())
				logging.Error("service.match.helper.AssetsBsub err1:", err)
				return err
			}
		}else {
			fields := rmc.Assets{
				Number: subNumber,
			}
			con := rmc.Condition{
				Id: assets[0].Id,
			}
           //不处理冻结资产
           err := mc.AssetsUpdate(&con, &fields)
			if err != nil {
				email.SendMail("service.match.helper.AssetsBsub err2", err.Error())
				logging.Error("service.match.helper AssetsBsub err2:", err)
				return err
			}
		}

	}
	return nil
}

//AssetsCAdd 买入 非基础币资产 增加
func AssetsCAdd(order *rmc.MCondition, buyFee, number float64) {
	condition := rmc.Condition{
		UId: order.Uid,
		CurrencyId: order.CurrencyId,
	}

	assets, err := mc.AssetsList(&condition)
	if err != nil {
		email.SendMail("service.match.helper.AssetsCAdd AssetsList", err.Error())
		logging.Error("service.match.helper.AssetsCAdd AssetsList err:", err)
	}


	bigNumber  := big.NewFloat(number)
	bigOne     := big.NewFloat(1)
	bigBuyFee  := big.NewFloat(buyFee)
	logging.Info("service.match.helper.AssetsCAdd bigNumber:", bigNumber)
	logging.Info("service.match.helper.AssetsCAdd bigBuyFee:", bigBuyFee)

	num := bigOne.Sub(bigOne, bigBuyFee)
	logging.Info("service.match.helper.AssetsCAdd num:", num)

	numberC, _    := num.Mul(num, bigNumber).Float64()
	logging.Info("service.match.helper.AssetsCAdd numberC:", numberC)

	if len(assets) == 0 {
		 fields := rmc.Assets{
		 	UId: order.Uid,
		 	CurrencyId: order.CurrencyId,
		 	Number: numberC,
		 }
         mc.AssetsAdd(&fields)
	}else {
		con := rmc.Condition{
			Id: assets[0].Id,
		}

		assetsNumber := big.NewFloat(assets[0].Number)
		bigNumberC   := big.NewFloat(numberC)
		logging.Info("service.match.helper.AssetsCAdd assetsNumber:", assetsNumber)
		logging.Info("service.match.helper.AssetsCAdd bigNumberC:", bigNumberC)

		numC, _      := assetsNumber.Add(assetsNumber, bigNumberC).Float64()
		logging.Info("service.match.helper.AssetsCAdd numC:", numC)

		fields := rmc.Assets{
			Number: numC,
		}
		err := mc.AssetsUpdate(&con, &fields)
		if err != nil {
			email.SendMail("service.match.helper.AssetsCAdd AssetsUpdate", err.Error())
			logging.Error("service.match.helper.AssetsCAdd AssetsUpdate err:", err)
		}
	}
}

//AssetsBAdd 卖出 基础币资产增加
func AssetsBAdd(order *rmc.MCondition, number, sellFee, price float64) {
	condition := rmc.Condition{
		UId: order.Uid,
		CurrencyId: order.BaseCurrencyId,
	}

	assets, err := mc.AssetsList(&condition)
	if err != nil {
		email.SendMail("service.match.helper.AssetsBAdd AssetsList", err.Error())
		logging.Error("service.match.helper.AssetsBAdd AssetsList err:", err)
	}

	bigNumber   := big.NewFloat(number)
	bigOne      := big.NewFloat(1)
	bigSellFee  := big.NewFloat(sellFee)
	bigPrice    := big.NewFloat(price)
	logging.Info("service.match.helper.AssetsBAdd bigNumber:", bigNumber)
	logging.Info("service.match.helper.AssetsBAdd bigSellFee:", bigSellFee)
	logging.Info("service.match.helper.AssetsBAdd bigPrice:", bigPrice)


	num  := bigOne.Sub(bigOne, bigSellFee)
	logging.Info("service.match.helper.AssetsBAdd num:", num)

	num2 := num.Mul(num, bigNumber)
	logging.Info("service.match.helper.AssetsBAdd num2:", num2)

	numberB, _ := num2.Mul(num2, bigPrice).Float64()
	logging.Info("service.match.helper.AssetsBAdd numberB:", numberB)

	if len(assets) == 0 {
		fields := rmc.Assets{
			UId: order.Uid,
			CurrencyId: order.BaseCurrencyId,
			Number: numberB,
		}
		mc.AssetsAdd(&fields)
	}else {
		con := rmc.Condition{
			Id: assets[0].Id,
		}

		assetsNumber := big.NewFloat(assets[0].Number)
		bigNumberB   := big.NewFloat(numberB)
		logging.Info("service.match.helper.AssetsBAdd assetsNumber:", assetsNumber)
		logging.Info("service.match.helper.AssetsBAdd bigNumberB:", bigNumberB)

		numB, _      := assetsNumber.Add(assetsNumber, bigNumberB).Float64()
		logging.Info("service.match.helper.AssetsBAdd numB:", numB)


		fields := rmc.Assets{
			Number: numB,
		}

		err := mc.AssetsUpdate(&con, &fields)
		if err != nil {
			email.SendMail("service.match.helper.AssetsBAdd AssetsUpdate", err.Error())
			logging.Error("service.match.helper.AssetsBAdd AssetsUpdate err:", err)
		}
	}
}

//AssetsCSub 卖出 非基础币资产 减少
func AssetsCSub(order *rmc.MCondition, number float64) error{
	condition := rmc.Condition{
		UId: order.Uid,
		CurrencyId: order.CurrencyId,
	}

	assets, err := mc.AssetsList(&condition)
	if err != nil {
		email.SendMail("service.match.helper.AssetsCSub AssetsList", err.Error())
		logging.Error("service.match.helper.AssetsCSub AssetsList err:", err)
	}


	if len(assets) == 0 {
		return errors.New("service.match.helper AssetsCSub 没有资产")
	}else {

		assetsNumber    := big.NewFloat(assets[0].Number)
		assetsNumberWtd := big.NewFloat(assets[0].NumberWtd)
		logging.Info("service.match.helper.AssetsCSub assetsNumber:", assetsNumber)
		logging.Info("service.match.helper.AssetsCSub assetsNumberWtd:", assetsNumberWtd)


		//减
		numberCanUse, _ := assetsNumber.Sub(assetsNumber, assetsNumberWtd).Float64()
		logging.Info("service.match.helper.AssetsCSub numberCanUse:", numberCanUse)

		if numberCanUse < number {
			return errors.New("service.match.helper AssetsBsub 非基础币资产不足")
		}

		//减
		bigNumber  := big.NewFloat(number)
		logging.Info("service.match.helper.AssetsCSub bigNumber:", bigNumber)

		subNumber, _ := assetsNumber.Sub(assetsNumber, bigNumber).Float64()
		logging.Info("service.match.helper.AssetsCSub subNumber:", subNumber)


		//市价买入单不需要冻结资产，其他需要
		if order.Tradetype == 0 || order.Type == 0 {
			frzNumber :=big.NewFloat(assets[0].NumberFrz)
			logging.Info("service.match.helper.AssetsCSub frzNumber:", frzNumber)

			//减
			subFreeze , _ := frzNumber.Sub(frzNumber, bigNumber).Float64()
			logging.Info("service.match.helper.AssetsCSub subFreeze:", subFreeze)

			if subFreeze < 0 {
				return errors.New("service.match.helper AssetsBsub 非基础币冻结资产不足")
			}

			fields := rmc.Assets{
				Number: subNumber,
				NumberFrz: subFreeze,
			}

			con := rmc.Condition{
				Id: assets[0].Id,
			}
			err := mc.AssetsUpdate(&con, &fields)
			if err != nil {
				email.SendMail("service.match.helper.AssetsBsub err1", err.Error())
				logging.Error("service.match.helper.AssetsBsub err1:", err)
				return err
			}
		}else {
			fields := rmc.Assets{
				Number: subNumber,
			}
			con := rmc.Condition{
				Id: assets[0].Id,
			}
			//不处理冻结资产
			err := mc.AssetsUpdate(&con, &fields)
			if err != nil {
				email.SendMail("service.match.helper.AssetsBsub err1", err.Error())
				logging.Error("service.match.helper.AssetsBsub err2:", err)
				return err
			}
		}

	}
	return nil
}



















